package top.meijhm.communitymanagement.user.service;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import top.meijhm.communitymanagement.common.auth.security.SecurityConfig;
import top.meijhm.communitymanagement.common.exceptions.DatabaseOperationException;
import top.meijhm.communitymanagement.common.exceptions.ObjectConflictException;
import top.meijhm.communitymanagement.common.exceptions.ObjectNotFoundException;
import top.meijhm.communitymanagement.common.exceptions.ParamCheckFailedException;
import top.meijhm.communitymanagement.user.model.User;
import top.meijhm.communitymanagement.user.model.UserRole;
import top.meijhm.communitymanagement.user.repository.UserRepository;

import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private SecurityConfig securityConfig;

    public User getUserById(Long id) {
        return userRepository.findByIdAndDeleted(id, false);
    }

    public User getUserByName(String username) {
        return userRepository.findByUsernameAndDeleted(username, false);
    }

    public List<User> getUsersByRole(String userRoleString) throws ObjectNotFoundException {
        List<User> user;
        if (UserRole.ROLE_USER.name().equalsIgnoreCase(userRoleString)) {
            user = userRepository.findAllByUserRoleAndDeleted(UserRole.ROLE_USER, false);
        } else if (UserRole.ROLE_ADMIN.name().equalsIgnoreCase(userRoleString)) {
            user = userRepository.findAllByUserRoleAndDeleted(UserRole.ROLE_ADMIN, false);
        } else {
            throw new ObjectNotFoundException(String.format("没找到用户角色：%s", userRoleString));
        }
        return user;
    }

    public List<User> getUsers() {
        return userRepository.findAllByDeleted(false);
    }

    public Page<User> getPageUsers(Integer page, Integer size) {
        page = page < 0 ? 0 : page;
        size = size < 1 ? 1 : size;
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        Pageable pageable = PageRequest.of(page, size, sort);
        return userRepository.findAllByDeleted(pageable, false);
    }

    public User addUser(User user) throws ObjectConflictException {
        if (userRepository.findByUsernameAndDeleted(user.getUsername(), false) != null) {
            throw new ObjectConflictException(String.format("用户名：%s 已存在", user.getUsername()));
        }
        if (user.getEnabled() == null) {
            user.setEnabled(true);
        }
        user.setPassword(securityConfig.passwordEncoder().encode(user.getPassword()));
        user.setDeleted(false);
        user.setCreatedTime(new Date());
        user.setUpdatedTime(new Date());
        return userRepository.saveAndFlush(user);
    }

    public void dropUserByName(String username) throws ObjectNotFoundException {
        if (userRepository.findByUsername(username) == null) {
            throw new ObjectNotFoundException("删除的用户不存在，请检查输入的用户名");
        }
        userRepository.dropUserByName(username);
    }

    public void deleteUserById(Long id) throws Exception {
        User user;
        try {
            user = userRepository.findByIdAndDeleted(id, false);
        } catch (Exception e) {
            throw new DatabaseOperationException(e.getMessage());
        }
        if (user == null) {
            throw new ObjectNotFoundException(String.format("user id %s not found", id));
        }
        deleteUser(user);
    }

    public void deleteUserByName(String username) throws Exception {
        User user;
        try {
            user = userRepository.findByUsernameAndDeleted(username, false);
        } catch (Exception e) {
            throw new DatabaseOperationException(e.getMessage());
        }
        if (user == null) {
            throw new ObjectNotFoundException(String.format("user %s not found", username));
        }
        deleteUser(user);
    }

    private void deleteUser(User user) {
        user.setDeleted(true);
        user.setUpdatedTime(new Date());
        userRepository.saveAndFlush(user);
    }

    public User updateUser(User user) throws Exception {
        if (user.getUsername() != null) {
            throw new ParamCheckFailedException("Username can not be updated.");
        }
        if (user.getDeleted() != null) {
            throw new ParamCheckFailedException("Deleted can not be updated.");
        }
        if (user.getEnabled() != null) {
            throw new ParamCheckFailedException("Enabled can not be updated.");
        }
        if (user.getCreatedTime() != null) {
            throw new ParamCheckFailedException("CreatedTime can not be updated.");
        }
        if (user.getUpdatedTime() != null) {
            throw new ParamCheckFailedException("UpdatedTime can not be updated.");
        }

        User res;
        try {
            res = userRepository.findByIdAndDeleted(user.getId(), false);
        } catch (Exception e) {
            throw new DatabaseOperationException(e.getMessage());
        }
        if (res == null) {
            throw new ObjectNotFoundException(String.format("user %s deleted or not exist", user.getUsername()));
        }

        if (StrUtil.isNotBlank(user.getPassword())) {
            res.setPassword(securityConfig.passwordEncoder().encode(user.getPassword()));
        }
        if (user.getDescription() != null) {
            res.setDescription(user.getDescription());
        }
        if (user.getUserRole() != null) {
            res.setUserRole(user.getUserRole());
        }

        try {
            return userRepository.saveAndFlush(res);
        } catch (Exception e) {
            throw new DatabaseOperationException(e.getMessage());
        }
    }
}